#pragma once
#include <iostream>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>

// 响应
// 服务器发送给客户端一个响应
struct Response
{
public:
    Response()
    {}
    
    Response(int res)
        : _res(res)
    {
    }
    Response(int eno, std::string errStr)
        : _errno(eno), _errStr(errStr)
    {
    }
    int _res = 0 ;
    int _errno = 0;
    std::string _errStr = "";

public:
    // 序列化
    // struct -> string
    // const & ： 输入型参数
    //       * ： 输出型参数
    void Serialize(std::string *str)
    {
        // 1.构建Json对象
        Json::Value val;
        val["_res"] = _res;
        val["_errno"] = _errno;
        val["_errStr"] = _errStr;
        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> psw(swb.newStreamWriter());
        // 2.序列化
        std::ostringstream oss;
        psw->write(val, &oss);
        *str = oss.str();
    }
    // 反序列化
    // string -> struct
    void DisSerialize(const std::string &str)
    {
        Json::Value val;
        Json::CharReaderBuilder crb;
        // 1. 反序列化
        std::unique_ptr<Json::CharReader> pcr(crb.newCharReader());
        std::string err;
        pcr->parse(str.c_str(), str.c_str() + str.size(), &val, &err);
        // 2. 填充 Reponse
        _res = val["_res"].asInt();
        _errno = val["_errno"].asInt();
        _errStr = val["_errStr"].asString();
    }
};

// 请求
// 客户端发送给服务器一个请求
struct Request
{
public:
    Request()
    {}

    Request(int x, int y, char op)
        : _x(x), _y(y), _op(op)
    {
    }
    int _x;
    int _y;
    char _op;

public:
    // 序列化
    // struct -> string
    void Serialize(std::string *str)
    {
        // 1. 构建val对象
        Json::Value val;
        val["_x"] = _x;
        val["_y"] = _y;
        val["_op"] = _op;
        // 2.序列化
        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> psw(swb.newStreamWriter());
        std::ostringstream oss;
        psw->write(val, &oss);
        *str = oss.str();
    }
    // 反序列化
    // string -> struct
    void DisSerialize(const std::string &str)
    {
        // 1.反序列化
        Json::Value val;
        Json::CharReaderBuilder crb;
        std::unique_ptr<Json::CharReader> pcb(crb.newCharReader());
        std::string err;
        pcb->parse(str.c_str(), str.c_str() + str.size(), &val, &err);
        // 2.填充字段
        _x = val["_x"].asInt();
        _y = val["_y"].asInt();
        _op = val["_op"].asInt();
    }
};

#define SEPARATOR "\r\n"
#define HEAD_SEPARATOR " "

#define SEPARATOR_LEN strlen(SEPARATOR)

class Protocol
{
public:
    // 报头 + 有效载荷 + 分隔符
    // 报头：有效载荷的长度
    // 有效载荷：序列化的字符串
    // 分隔符 \r\n

    // const &: 输入
    //       &: 输入输出
    //       *: 输出

    // 15 xxxxxxxxx\r\n15xxxxxxxxxxxxx\r\n  缓冲区
    // 15xxxxxxxxx\r\n         报文
    // xxxxxxxxx     有效载荷

    // 添加报头
    // body：有效载荷&分隔符
    // xxxxxxxxxxxx
    // 15 xxxxxxxxxxxx\r\n
    static void AddHeader(std::string &body)
    {
        int len = body.size();
        std::string tmp = std::to_string(len);
        tmp += HEAD_SEPARATOR;
        tmp += body;
        tmp += SEPARATOR;
        body = tmp;
    }
    // 删除报头
    // message：报文&分隔符
    // 未来传给我的一定是一个有效的报文
    static std::string DelHeader(const std::string &message)
    {
        // cout << "DelHeader::message: " << message << endl;
        auto pos = message.find(HEAD_SEPARATOR, 0);
        // cout << "pos: "<< pos << endl;
        // cout << "len: " << message.substr(0, pos) << endl;
        int len = stoi(message.substr(0, pos));
        std::string body = message.substr(pos + 1, len);
        return body;
    }
    // 从缓冲区中获取一段报文
    // 可能会获取失败
    // 当获取到一段报文后，需要从缓冲区内部删除掉这段报文
    static bool GetMsg(std::string &buf, std::string *msg)
    {
         // 15 xxxxxxxxx\r\n15xxxxxxxxxxxxx\r\n  缓冲区
        auto pos = buf.find(SEPARATOR, 0);
        if (pos == std::string::npos)
            return false;
        *msg = buf.substr(0, pos);
        // 分隔符的长度并不是1！
        // 从buf中删除的时候要把分隔符的长度算上
        buf.erase(0,pos + SEPARATOR_LEN);
        return true;
    }
};